package com.tulei.crawler;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.xy.XYBubbleRenderer;
import org.jfree.chart.ui.ApplicationFrame;
import org.jfree.chart.ui.UIUtils;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.xy.DefaultXYZDataset;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import javax.swing.*;
import java.awt.*;
import java.awt.Font;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

public class WebLYScraperOne {

    // 爬取页数
    private static int MAX_PAGE = 5;

    public static void main(String[] args) throws IOException {
        String filePath = "TouristSpots.xlsx";

        // Step1: 抓取数据并存储在Excel文件中
        List<TouristSpot> list = scrapeDataAndStoreInExcel(filePath);

        createCombinedChart(list);
        // Step 2: 从Excel文件中读取数据
        Workbook workbook = new XSSFWorkbook(new FileInputStream(filePath));
        Sheet sheet = workbook.getSheetAt(0);

        // Step 3: 根据数据生成四个不同的图表
        generateCharts(sheet, workbook);

        // 将更新后的工作簿与图表一起保存
        try (FileOutputStream outputStream = new FileOutputStream(filePath)) {
            workbook.write(outputStream);
        }
        workbook.close();
    }

    private static List<TouristSpot> scrapeDataAndStoreInExcel(String filePath) throws IOException {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Tourist Spots");

        int rowNum = 0;
        Row headerRow = sheet.createRow(rowNum++);
        headerRow.createCell(0).setCellValue("Title");
        headerRow.createCell(1).setCellValue("Price");
        headerRow.createCell(2).setCellValue("Address");
        headerRow.createCell(3).setCellValue("Image URL");
        headerRow.createCell(4).setCellValue("Description");

        List<TouristSpot> list = new ArrayList<>();
        // 爬取多页数据
        for (int page = 1; page <= MAX_PAGE; page++) {
            String url = "http://piao.qunar.com/ticket/list.htm?keyword=%E5%8C%97%E4%BA%AC&region=&from=mpl_search_suggest&page=" + page;
            Document doc = Jsoup.connect(url).get();
            // 查找class名字为sight_item的内容
            Elements elements = doc.select(".sight_item");

            for (Element element : elements) {
                Row row = sheet.createRow(rowNum++);

                TouristSpot touristSpot = new TouristSpot();
                String title = element.attr("data-sight-name");
                String priceText = element.select(".sight_item_price em").text().replaceAll("[^\\d.]", "");
                double price = priceText.isEmpty() ? 0 : Double.parseDouble(priceText);
                String address = element.attr("data-address");
                String imageUrl = element.attr("data-sight-img-u-r-l");
                String description = element.select(".intro").text();

                row.createCell(0).setCellValue(title);
                row.createCell(1).setCellValue(price);
                row.createCell(2).setCellValue(address);
                row.createCell(3).setCellValue(imageUrl);
                row.createCell(4).setCellValue(description);
                touristSpot.setTitle(title);
                touristSpot.setPrice(price);
                touristSpot.setAddress(address);
                touristSpot.setImageUrl(imageUrl);
                touristSpot.setDescription(description);
                list.add(touristSpot);
            }
        }

        try (FileOutputStream outputStream = new FileOutputStream(filePath)) {
            workbook.write(outputStream);
        }
        workbook.close();
        return list;
    }

    private static void generateCharts(Sheet sheet, Workbook workbook) throws IOException {
        DefaultCategoryDataset priceDataset = new DefaultCategoryDataset();
        DefaultCategoryDataset addressDataset = new DefaultCategoryDataset();
        DefaultCategoryDataset descriptionDataset = new DefaultCategoryDataset();
        DefaultCategoryDataset titleLengthDataset = new DefaultCategoryDataset();

        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            String title = row.getCell(0).getStringCellValue();
            double price = row.getCell(1).getNumericCellValue();
            String address = row.getCell(2).getStringCellValue();
            String description = row.getCell(4).getStringCellValue();

            priceDataset.addValue(price, "Price", title);
            addressDataset.addValue(1, "Count", address);
            descriptionDataset.addValue(1, "Count", description);
            titleLengthDataset.addValue(title.length(), "Title Length", title);
        }

        createChart(workbook, sheet, "Tourist Spots Price", "Title", "Price", priceDataset, 1);
        createChart(workbook, sheet, "Tourist Spots by Address", "Address", "Count", addressDataset, 21);
        createChart(workbook, sheet, "Tourist Spots Descriptions", "Description", "Count", descriptionDataset, 41);
        createChart(workbook, sheet, "Tourist Spots Title Length", "Title", "Length", titleLengthDataset, 61);
    }


    private static void createCombinedChart(List<TouristSpot> touristSpots) {
        ApplicationFrame frame = new ApplicationFrame("Charts");

        // 创建四个图表的面板
        ChartPanel pieChartPanel = new ChartPanel(createPieChart(touristSpots));
        ChartPanel barChartPanel = new ChartPanel(createBarChart(touristSpots));
        ChartPanel lineChartPanel = new ChartPanel(createLineChart(touristSpots));
        ChartPanel scatterPlotPanel = new ChartPanel(createBubbleChart(touristSpots));

        // 使用 GridLayout 布局将四个图表面板放在同一个窗口中
        JPanel panel = new JPanel(new GridLayout(2, 2));
        panel.add(pieChartPanel);
        panel.add(barChartPanel);
        panel.add(lineChartPanel);
        panel.add(scatterPlotPanel);

        frame.setContentPane(panel);
        frame.pack();
        UIUtils.centerFrameOnScreen(frame);
        frame.setVisible(true);
    }

    private static JFreeChart createPieChart(List<TouristSpot> touristSpots) {
        Map<String, Integer> titleCount = new HashMap<>();
        for (TouristSpot touristSpot : touristSpots) {
            String title = touristSpot.getTitle();
            titleCount.put(title, titleCount.getOrDefault(title, 0) + 1);
        }

        DefaultPieDataset dataset = new DefaultPieDataset();
        for (Map.Entry<String, Integer> entry : titleCount.entrySet()) {
            dataset.setValue(entry.getKey(), entry.getValue());
        }

        JFreeChart pieChart = ChartFactory.createPieChart(
                "饼状分布图",
                dataset,
                true, true, false);

        PiePlot plot = (PiePlot) pieChart.getPlot();
        plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}: {1}"));

        // 使用系统字体以支持中文字符
        Font font = Font.decode("SansSerif-PLAIN-12");
        plot.setLabelFont(font);
        pieChart.getTitle().setFont(font);
        pieChart.getLegend().setItemFont(font);
        return pieChart;
    }

    private static JFreeChart createBarChart(List<TouristSpot> touristSpots) {
        Map<Integer, Integer> addressLengthCount = new HashMap<>();
        for (TouristSpot touristSpot : touristSpots) {
            String address = touristSpot.getAddress();
            int addressLength = address.length();
            addressLengthCount.put(addressLength, addressLengthCount.getOrDefault(addressLength, 0) + 1);
        }

        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        for (Map.Entry<Integer, Integer> entry : addressLengthCount.entrySet()) {
            dataset.addValue(entry.getValue(), "Number of Addresses", entry.getKey());
        }

        JFreeChart barChart = ChartFactory.createBarChart(
                "地区名称长度分布",
                "地址长度",
                "数量",
                dataset,
                PlotOrientation.VERTICAL,
                true, true, false);

        CategoryPlot plot = (CategoryPlot) barChart.getPlot();
        // 设置中文字体
        Font chineseFont = new Font("宋体", Font.PLAIN, 12);
        plot.getDomainAxis().setLabelFont(chineseFont);
        plot.getDomainAxis().setTickLabelFont(chineseFont);
        plot.getRangeAxis().setLabelFont(chineseFont);
        barChart.getTitle().setFont(chineseFont);
        barChart.getLegend().setItemFont(chineseFont);

        return barChart;
    }

    private static JFreeChart createLineChart(List<TouristSpot> touristSpots) {
        Map<Double, Integer> priceCount = new HashMap<>();
        for (TouristSpot touristSpot : touristSpots) {
            double price = touristSpot.getPrice();
            priceCount.put(price, priceCount.getOrDefault(price, 0) + 1);
        }

        DefaultCategoryDataset dataset = new DefaultCategoryDataset();
        for (Map.Entry<Double, Integer> entry : priceCount.entrySet()) {
            dataset.addValue(entry.getValue(), "Numbers", entry.getKey());
        }

        JFreeChart lineChart = ChartFactory.createLineChart(
                "价格折线图",
                "价格",
                "Numbers",
                dataset,
                PlotOrientation.VERTICAL,
                true, true, false);

        CategoryPlot plot = (CategoryPlot) lineChart.getPlot();
        Font font = Font.decode("SansSerif-PLAIN-12");
        plot.getDomainAxis().setLabelFont(font);
        plot.getRangeAxis().setLabelFont(font);
        lineChart.getTitle().setFont(font);
        lineChart.getLegend().setItemFont(font);

        // 设置折线图的渲染器
        LineAndShapeRenderer renderer = new LineAndShapeRenderer();
        plot.setRenderer(renderer);

        return lineChart;
    }

    public static JFreeChart createBubbleChart(List<TouristSpot> touristSpots) {
        DefaultXYZDataset dataset = new DefaultXYZDataset();

        // 为每个作者创建一个系列
        touristSpots.stream().map(TouristSpot::getAddress).distinct().forEach(address -> {
            List<TouristSpot> addressList = touristSpots.stream()
                    .filter(touristSpot -> touristSpot.getAddress().equals(address))
                    .collect(Collectors.toList());

            double[][] data = new double[3][addressList.size()];

            for (int i = 0; i < addressList.size(); i++) {
                TouristSpot touristSpot = addressList.get(i);
                double titleLength = touristSpot.getTitle().length();
                double authorNameLength = touristSpot.getAddress().length();
                double descriptionSize = touristSpot.getDescription().length() / 10;
                data[0][i] = titleLength;
                data[1][i] = authorNameLength;
                data[2][i] = descriptionSize;
            }

            dataset.addSeries(address, data);
        });

        JFreeChart bubbleChart = ChartFactory.createBubbleChart(
                "气泡图",
                "Title Length",
                "address Length",
                dataset,
                PlotOrientation.VERTICAL,
                true, true, false);

        XYPlot plot = (XYPlot) bubbleChart.getPlot();
        XYBubbleRenderer renderer = new XYBubbleRenderer();
        plot.setRenderer(renderer);

        Font font = Font.decode("SansSerif-PLAIN-12");
        plot.getDomainAxis().setLabelFont(font);
        plot.getRangeAxis().setLabelFont(font);
        bubbleChart.getTitle().setFont(font);
        bubbleChart.getLegend().setItemFont(font);

        return bubbleChart;
    }
    private static void createChart(Workbook workbook, Sheet sheet, String chartTitle, String xAxisLabel, String yAxisLabel, DefaultCategoryDataset dataset, int startRow) throws IOException {
        JFreeChart chart = ChartFactory.createBarChart(
                chartTitle,
                xAxisLabel,
                yAxisLabel,
                dataset,
                PlotOrientation.VERTICAL,
                true, true, false);

        // Tilt the x-axis labels and set font
        CategoryPlot plot = chart.getCategoryPlot();
        CategoryAxis xAxis = plot.getDomainAxis();
        xAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45);
        xAxis.setTickLabelFont(new Font("Serif", Font.PLAIN, 10));

        int width = 640;
        int height = 480;
        ByteArrayOutputStream chartOut = new ByteArrayOutputStream();
        ChartUtils.writeChartAsJPEG(chartOut, chart, width, height);

        int pictureIdx = workbook.addPicture(chartOut.toByteArray(), Workbook.PICTURE_TYPE_JPEG);
        chartOut.close();

        //Jframe

        XSSFDrawing drawing = (XSSFDrawing) sheet.createDrawingPatriarch();
        XSSFClientAnchor anchor = new XSSFClientAnchor();
        anchor.setCol1(0);
        anchor.setRow1(startRow);
        anchor.setCol2(10);
        anchor.setRow2(startRow + 20);
        drawing.createPicture(anchor, pictureIdx);
    }
}


class TouristSpot {
    private String title;
    private double price;
    private String address;
    private String imageUrl;
    private String description;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getImageUrl() {
        return imageUrl;
    }

    public void setImageUrl(String imageUrl) {
        this.imageUrl = imageUrl;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

}